'use strict';

const fs = require('fs-extra');
const path = require('path');
const awaitWriteStream = require('await-stream-ready').write;
const sendToWormhole = require('stream-wormhole');

const Controller = require('egg').Controller;

class UploadFileController extends Controller {

    /**
     * 上传单个文件
     */
    async uploadSingleFile() {
        const ctx = this.ctx;
        let userid = ctx.get('uid'); //获取登录者id
        try {
            if (ctx.helper.verifyToken(ctx, userid)) {
                const stream = await ctx.getFileStream();
                //新建一个文件名
                const filename = ctx.helper.getGuid16() + path
                    .extname(stream.filename)
                    .toLocaleLowerCase();

                const filePath = path.join(this.config.baseDir, 'app/public/public');
                ctx.helper.mkdirsForCustom(filePath);
                const target = path.join(filePath, filename);
                //生成一个文件写入 文件流
                const writeStream = fs.createWriteStream(target);
                try {
                    //异步把文件流 写入
                    await awaitWriteStream(stream.pipe(writeStream));
                } catch (err) {
                    //如果出现错误，关闭管道
                    await sendToWormhole(stream);
                    throw err;
                }
                ctx.status = 200;
                ctx.body = {
                    code: 1,
                    msg: ctx.__('uploadOk'),
                    url: '/public/public/' + filename,
                    filename: filename
                };
            }
        } catch (error) {
            ctx.status = 500;
            ctx.body = {
                code: -1,
                msg: error.message
            };
        }
    };

    /**
     * 上传多个文件
     */
    async uploadMultipartFile() {
        const ctx = this.ctx;
        let userid = ctx.get('uid'); //获取登录者id
        try {
            if (ctx.helper.verifyToken(ctx, userid)) {
                const files = ctx.multipart({ autoFields: true }); //获取文件列表
                //先判断文件夹是否存在，如果不存在则创建
                const filePath = path.join(this.config.baseDir, 'app/public/public');
                ctx.helper.mkdirsForCustom(filePath);
                let result = []; //返回上传成功的文件地址
                try {
                    let stream; //接收文件上传文件流
                    while ((stream = await files()) != null) {
                        if (!stream.length) {
                            //用户未选择对应的文件就执行上传操作
                            if (!stream.filename) {
                                return;
                            }
                            //新建一个文件名
                            const filename = ctx.helper.getGuid16() + path
                                .extname(stream.filename)
                                .toLocaleLowerCase();
                            const target = path.join(filePath, filename);
                            //生成一个文件写入 文件流
                            const writeStream = fs.createWriteStream(target);
                            try {
                                //异步把文件流 写入
                                await awaitWriteStream(stream.pipe(writeStream));
                                result.push('/public/public/' + filename);
                            } catch (err) {
                                //如果出现错误，关闭管道
                                await sendToWormhole(stream);
                                throw err;
                            }
                        }
                    }
                } finally {
                    await ctx.cleanupRequestFiles();
                }
                console.log(files.field) //只有文件读取完毕之后，才能获取到携带的数据
                ctx.status = 200;
                ctx.body = {
                    code: 1,
                    msg: ctx.__('uploadOk'),
                    urls: result
                };
            }
        } catch (error) {
            ctx.status = 500;
            ctx.body = {
                code: -1,
                msg: error.message
            };
        }
    };

    /**
     * 新版本文件分片上传
     */
    async addFragFile() {
        const {
            ctx
        } = this;
        const userid = ctx.get('uid'); //获取登录者id
        try {
            if (ctx.helper.verifyToken(ctx, userid)) {
                //#region 判断文件夹是否存在
                let filePath = path.join(this.config.baseDir, 'app/public/public');
                ctx.helper.mkdirsForCustom(filePath);
                //#endregion

                //#region 获取文件相关信息
                const stream = await ctx.getFileStream(); //读取文件流
                const fields = stream.fields;//获取携带的字段数据
                const total = parseInt(fields["total"]); //切片总数目
                const index = parseInt(fields["index"]); //当前文件上传的索引位置 从0开始
                const extname = fields["extname"]; //文件扩展名               
                let fileMd5Value = fields["fileMd5Value"]; //文件名称，唯一标识
                let filename = ""; //新建一个文件名
                //#endregion

                //#region 文件名创建
                if (total === (index + 1)) {
                    if (total !== 1) {
                        filename = index + fileMd5Value; //文件名    
                        //临时文件夹                 
                        filePath = path.join(this.config.baseDir, `app/public/public/tmp/${fileMd5Value}`);
                        ctx.helper.mkdirsForCustom(filePath);
                    } else {
                        filename = ctx.helper.getGuid16() + extname; //文件名
                    }
                } else {
                    filename = index + fileMd5Value; //文件名
                    //临时文件夹
                    filePath = path.join(this.config.baseDir, `app/public/public/tmp/${fileMd5Value}`);
                    ctx.helper.mkdirsForCustom(filePath);
                }
                //#endregion

                //#region 文件写入操作
                let target = path.join(filePath, filename);
                //生成一个文件写入 文件流
                const writeStream = fs.createWriteStream(target);
                try {
                    //异步把文件流 写入
                    await awaitWriteStream(stream.pipe(writeStream));
                } catch (err) {
                    //如果出现错误，关闭管道
                    await sendToWormhole(stream);
                    throw err;
                }
                //#endregion

                //#region 文件转移操作
                const fileUrl = path.join(this.config.baseDir, `app/public/public/${filename}`);//上传的文件地址
                //判断文件夹是否存在
                filePath = path.join(this.config.baseDir, 'app/public/updateFiles');
                ctx.helper.mkdirsForCustom(filePath);
                let destPath = path.join(filePath, filename);
                fs.rename(fileUrl, destPath, function (err) {
                    if (err) throw err;
                    fs.stat(destPath, function (err, stats) {
                        if (err) throw err;
                        console.log('stats: ' + JSON.stringify(stats));
                    });
                });

                ctx.status = 200;
                if (total === (index + 1)) {
                    if (total === 1) {
                        ctx.body = {
                            code: 1,
                            msg: ctx.__('uploadOk'),
                            index: index + 1,
                            url: '/public/updateFiles/' + filename
                        };
                    } else {
                        //#region 执行文件合并操作
                        filename = ctx.helper.getGuid16() + extname; //文件名
                        let mergeFilePath = path.join(this.config.baseDir, `app/public/public/${filename}`); //最后合并文件地址
                        let srcDirPath = path.join(this.config.baseDir, `app/public/public/tmp/${fileMd5Value}`); //分片文件的基础目录
                        try {
                            // 按照分割的数据块顺序组装这个文件
                            let chunkPaths = await ctx.helper.listDir(srcDirPath)
                            chunkPaths.sort((x, y) => {
                                return x - y;
                            })
                            // 把文件名加上文件夹的前缀
                            for (let i = 0; i < chunkPaths.length; i++) {
                                chunkPaths[i] = srcDirPath + '/' + chunkPaths[i];
                            }
                            //#region 采用Stream方式合并
                            const targetStream = fs.createWriteStream(mergeFilePath);
                            const readStream = function (chunkArray) {
                                const path = chunkArray.shift();
                                const originStream = fs.createReadStream(path);
                                originStream.pipe(targetStream, {
                                    end: false
                                });
                                originStream.on('end', function () {
                                    // 删除文件
                                    fs.unlinkSync(path);
                                    if (chunkArray.length > 0) {
                                        readStream(chunkArray);
                                    } else {
                                        targetStream.close();
                                        originStream.close();
                                        fs.rmdirSync(srcDirPath);
                                    }
                                });
                            };
                            readStream(chunkPaths);
                            //#endregion
                        } catch (ex) { //如果出现错误，关闭管道
                            await sendToWormhole(stream);
                            throw ex;
                        } finally {
                            ctx.body = {
                                code: 1,
                                msg: ctx.__('uploadOk'),
                                index: index + 1,
                                url: '/public/updateFiles/' + filename
                            };
                        }
                        //#endregion
                    }
                } else {
                    ctx.body = {
                        code: 0,
                        msg: "请继续上传文件",
                        index: index + 1
                    };
                }
            }
        } catch (err) {
            console.log(err);
            ctx.status = 500;
            ctx.body = {
                code: -1,
                msg: err.message
            };
        }
    };

    /**
     * 获取已经上传的文件列表信息数据
     */
    async getChunkFileList() {
        const ctx = this.ctx;
        const userid = ctx.get('uid'); //获取登录者id
        try {
            if (ctx.helper.verifyToken(ctx, userid)) {
                let fileMd5Value = ctx.request.query["md5Val"]; //文件名称，唯一标识
                const fileUrl = path.join(this.config.baseDir, `app/public/public/tmp/${fileMd5Value}`);
                if (!fs.existsSync(fileUrl)) {
                    ctx.status = 200;
                    ctx.body = {
                        code: 1,
                        fileList: [], //已上传的文件信息
                        msg: "未上传任何文件"
                    };
                } else {
                    let files = fs.readdirSync(fileUrl);
                    let len = files.length;
                    if (len > 0) {
                        let fileList = [];
                        files.forEach(function (file) {
                            fileList.push(file);
                        })
                        ctx.status = 200;
                        ctx.body = {
                            code: 1,
                            fileList, //已上传的文件信息
                            msg: ctx.__('getDataSuccess')
                        };
                    } else {
                        ctx.status = 200;
                        ctx.body = {
                            code: 1,
                            fileList: [], //已上传的文件信息
                            msg: "未上传任何文件"
                        };
                    }
                }
            }
        } catch (err) {
            ctx.status = 500;
            ctx.body = {
                code: -1,
                msg: err.message
            };
        }
    }

    /**
     * 获取最后一个文件上传索引，用于断点续传
     * @returns {Promise<void>}
     */
    async getLastFileIndex() {
        const ctx = this.ctx;
        const userid = ctx.get('uid'); //获取登录者id
        try {
            if (ctx.helper.verifyToken(ctx, userid)) {
                let fileMd5Value = ctx.request.query["md5Val"]; //文件名称，唯一标识
                const fileUrl = path.join(this.config.baseDir, `app/public/public/tmp/${fileMd5Value}`);
                if (!fs.existsSync(fileUrl)) {
                    ctx.status = 200;
                    ctx.body = {
                        code: 1,
                        lastIndex: 0, //上传索引
                        msg: ctx.__('getDataSuccess')
                    };
                } else {
                    let files = fs.readdirSync(fileUrl);
                    files.sort();
                    let len = files.length;
                    if (len > 0) {
                        if (len > 1) {
                            let file1 = fs.statSync(path.join(fileUrl, files[len - 2]));//倒数第二个文件
                            let file2 = fs.statSync(path.join(fileUrl, files[len - 1]));//倒数第一个文件
                            if (file1.size !== file2.size) {//最后一个切割是不完整的
                                // 删除倒数第一个文件
                                fs.unlinkSync(path.join(fileUrl, files[len - 1]));
                                ctx.status = 200;
                                ctx.body = {
                                    code: 1,
                                    lastIndex: len - 1, //上传索引
                                    msg: ctx.__('getDataSuccess')
                                };
                            } else {
                                ctx.status = 200;
                                ctx.body = {
                                    code: 1,
                                    lastIndex: len, //上传索引
                                    msg: ctx.__('getDataSuccess')
                                };
                            }

                        } else {
                            ctx.status = 200;
                            ctx.body = {
                                code: 1,
                                lastIndex: 0, //上传索引
                                msg: ctx.__('getDataSuccess')
                            };
                        }
                        let fileList = [];
                        files.forEach(function (file) {
                            fileList.push(file);
                        })
                        ctx.status = 200;
                        ctx.body = {
                            code: 1,
                            fileList, //已上传的文件信息
                            msg: ctx.__('getDataSuccess')
                        };
                    } else {
                        ctx.status = 200;
                        ctx.body = {
                            code: 1,
                            lastIndex: 0, //上传索引
                            msg: ctx.__('getDataSuccess')
                        };
                    }
                }
            }
        } catch (err) {
            ctx.status = 500;
            ctx.body = {
                code: -1,
                msg: err.message
            };
        }
    }

    /**
     * 上传错误日志
     */
    async uploadErrorLog() {
        const ctx = this.ctx;
        let userid = ctx.get('uid'); //获取登录者id
        try {
                const stream = await ctx.getFileStream();
                //新建一个文件名
                let fileName = `${userid}_`+ ctx.helper.getGuid16(); 
                const filename = fileName + path
                    .extname(stream.filename)
                    .toLocaleLowerCase();

                const filePath = path.join(this.config.baseDir, 'app/public/errorLog');
                ctx.helper.mkdirsForCustom(filePath);
                const target = path.join(filePath, filename);
                //生成一个文件写入 文件流
                const writeStream = fs.createWriteStream(target);
                try {
                    //异步把文件流 写入
                    await awaitWriteStream(stream.pipe(writeStream));
                } catch (err) {
                    //如果出现错误，关闭管道
                    await sendToWormhole(stream);
                    throw err;
                }
                ctx.status = 200;
                ctx.body = {
                    code:1,
                    msg: 'ok'
                };
        } catch (error) {
	    console.log(error)
            ctx.status = 500;
            ctx.body = {
                code: 0,
                msg: "error"
            };
        }
    };

    
    /**
     * 上传音频文件
     */
     async uploadAudioFile() {
        const ctx = this.ctx;
        let userid = ctx.get('uid'); //获取登录者id
        try {
		if( userid === undefined || userid === ''){
		  userid = ctx.query.uid 
		}
                const stream = await ctx.getFileStream();
                //新建一个文件名
                let fileName = ctx.helper.getGuid16(); 
                const filename = fileName + path
                    .extname(stream.filename)
                    .toLocaleLowerCase();

                const filePath = path.join(this.config.baseDir, 'app/public/audio');
                ctx.helper.mkdirsForCustom(filePath);
                const target = path.join(filePath, filename);
                //生成一个文件写入 文件流
                const writeStream = fs.createWriteStream(target);
                try {
                    //异步把文件流 写入
                    await awaitWriteStream(stream.pipe(writeStream));
                } catch (err) {
                    //如果出现错误，关闭管道
                    await sendToWormhole(stream);
                    throw err;
                }
		
		let  _fmt;
		if((_fmt = stream.filename.split('.')).length > 1){
		       _fmt = _fmt[1];
		}else{

		       _fmt ='unknow';
		}
                let _obj = {
                    name: stream.filename ,
                    uid: userid,
                    url: '/public/audio/' + filename,
                    aid: stream.fieldname,
                    fomat: _fmt ,
		    fname: filename,
                    time: new Date().getTime()

                };

                //插入用户数据库
                await ctx.model.Audiofile.create(_obj);

                ctx.status = 200;
                ctx.body = {
                    code:1,
		    data:_obj,	
                    msg: 'ok'
                };


                
        } catch (error) {
	 console.log(error)
            ctx.status = 500;
	    if(error !== undefined && JSON.stringify(error).indexOf('Invalid filename') != -1){
             ctx.body = {
                code: 2,
                msg:error
              };
	    }else{
		 ctx.body = {
                code: 0,
                msg:error
              };
	    }
        }
    };

    /**
     * 上传头像
     */
    async uploadAvatar() {
        const ctx = this.ctx;
        let userid = ctx.get('uid'); //获取登录者id
        try {
            if (ctx.helper.verifyToken(ctx, userid)) {
                const stream = await ctx.getFileStream();
                //新建一个文件名
                let fileName = 'avatar_' + userid;
                const filename = fileName + path
                    .extname(stream.filename)
                    .toLocaleLowerCase();

                const filePath = path.join(this.config.baseDir, 'app/public/userInfo/avatar');
                ctx.helper.mkdirsForCustom(filePath);
                const target = path.join(filePath, filename);
                //如果文件存在 提前先删除
                const isExistFile = await fs.existsSync(target);
                if (isExistFile) {
                    fs.unlinkSync(target);
                }
                //生成一个文件写入 文件流
                const writeStream = fs.createWriteStream(target);
                try {
                    //异步把文件流 写入
                    await awaitWriteStream(stream.pipe(writeStream));
                } catch (err) {
                    //如果出现错误，关闭管道
                    await sendToWormhole(stream);
                    throw err;
                }

                //插入用户数据库
                await ctx.model.Userinfo.update({
                    Img: filename
                }, {
                    where: {
                        id: userid
                    }
                });

                let returnData = {
                    code: 1,
                    msg: ctx.__('uploadOk'),
                    url: '/public/userInfo/avatar/' + filename,
                    filename: filename
                }
                ctx.status = 200;
                ctx.body = {
                    code: returnData.code,
                    msg: returnData.msg
                };
            }
        } catch (error) {
            ctx.status = 500;
            ctx.body = {
                code: 0,
                msg: "error"
            };
        }
    };

    /**
    * 上传拍传图片
    */
    async uploadClap() {
        const ctx = this.ctx;
        let userid = ctx.get('uid'); //获取登录者id
        try {
            if (ctx.helper.verifyToken(ctx, userid)) {
                const stream = await ctx.getFileStream();
                //新建一个文件名
                const filename = ctx.helper.getGuid16() + path
                    .extname(stream.filename)
                    .toLocaleLowerCase();

                const filePath = path.join(this.config.baseDir, 'app/public/userInfo/clap');
                ctx.helper.mkdirsForCustom(filePath);
                const target = path.join(filePath, filename);
                //生成一个文件写入 文件流
                const writeStream = fs.createWriteStream(target);
                try {
                    //异步把文件流 写入
                    await awaitWriteStream(stream.pipe(writeStream));
                } catch (err) {
                    //如果出现错误，关闭管道
                    await sendToWormhole(stream);
                    throw err;
                }

                let returnData = {
                    code: 1,
                    msg: ctx.__('uploadOk'),
                    url: '/public/userInfo/clap/' + filename,
                    filename: filename
                }

                const encryptDESObj = ctx.service.units.encryptDES(JSON.stringify(returnData)); //加密返回数据源
                ctx.status = 200;
                ctx.body = {
                    code: returnData.code,
                    msg: returnData.msg,
                    data: encryptDESObj.data,
                    key: encryptDESObj.publicKey
                };
            }
        } catch (error) {
            let returnData = {
                code: -1,
                msg: error.message
            }
            const encryptDESObj = ctx.service.units.encryptDES(JSON.stringify(returnData)); //加密返回数据源
            ctx.status = 500;
            ctx.body = {
                code: 1,
                msg: "error",
                data: encryptDESObj.data,
                key: encryptDESObj.publicKey
            };
        }
    };

    /**
   * 上传文件版本号
   */
    async uploadVersion() {
        const ctx = this.ctx;
        let userid = ctx.get('uid'); //获取登录者id
        try {
            if (ctx.helper.verifyToken(ctx, userid)) {
                const stream = await ctx.getFileStream();

                //新建一个文件名
                const filename = ctx.helper.getGuid16() + path
                    .extname(stream.filename)
                    .toLocaleLowerCase();

                const filePath = path.join(this.config.baseDir, 'app/public/userInfo/version');
                ctx.helper.mkdirsForCustom(filePath);
                const target = path.join(filePath, filename);
                //生成一个文件写入 文件流
                const writeStream = fs.createWriteStream(target);
                try {
                    //异步把文件流 写入
                    await awaitWriteStream(stream.pipe(writeStream));
                } catch (err) {
                    //如果出现错误，关闭管道
                    await sendToWormhole(stream);
                    throw err;
                }

                let returnData = {
                    code: 1,
                    msg: ctx.__('uploadOk'),
                    url: '/public/userInfo/avatar/' + filename,
                    filename: filename
                }

                const encryptDESObj = ctx.service.units.encryptDES(JSON.stringify(returnData)); //加密返回数据源
                ctx.status = 200;
                ctx.body = returnData;
            }
        } catch (error) {
            console.log(error);
            // 事务回滚
            let returnData = {
                code: -1,
                msg: error.message
            }
            const encryptDESObj = ctx.service.units.encryptDES(JSON.stringify(returnData)); //加密返回数据源
            ctx.status = 500;
            ctx.body = returnData
        }
    };

    /**
     * 上传身份证 - App端使用
     *  argc
     */
    async uploadIdentityCard() {
        const ctx = this.ctx;
        let userid = ctx.get('uid'); //获取登录者id
        let typeView = ctx.get('view'); //获取登录者id
        try {
            if (ctx.helper.verifyToken(ctx, userid)) {


                const stream = await ctx.getFileStream();
                //新建一个文件名
                let fileName =   ctx.helper.getGuid16();// typeView + "_" + userid;
                const filename = fileName + path
                    .extname(stream.filename)
                    .toLocaleLowerCase();

                const filePath = path.join(this.config.baseDir, 'app/public/userInfo/identityCard');
                ctx.helper.mkdirsForCustom(filePath);
                const target = path.join(filePath, filename);
                //生成一个文件写入 文件流
                const writeStream = fs.createWriteStream(target);
                try {
                    //异步把文件流 写入
                    await awaitWriteStream(stream.pipe(writeStream));
                } catch (err) {
                    //如果出现错误，关闭管道
                    await sendToWormhole(stream);
                    throw err;
                }
                let returnData = {
                    code: 1,
                    msg: ctx.__('uploadOk'),
                    url: '/public/userInfo/identityCard/' + filename,
                    filename: filename
                }
		//删除原先图片
		if(typeView !== ''){
                  console.log(typeView)
		  const delTarget = path.join(this.config.baseDir, 'app'+typeView);
                  console.log(delTarget)
                  //如果文件存在 提前先删除
                  const isExistFile = await fs.existsSync(delTarget);
                  if (isExistFile) {
                      fs.unlinkSync(delTarget);
                  }
		}
                const encryptDESObj = ctx.service.units.encryptDES(JSON.stringify(returnData)); //加密返回数据源
                ctx.status = 200;
                ctx.body = {
                    code: 1,
                    msg: ctx.__('getDataSuccess'),
                    data: encryptDESObj.data,
                    key: encryptDESObj.publicKey
                };
            }
        } catch (error) {
            console.log(error);
            let returnData = {
                code: -1,
                msg: error.message
            }
            const encryptDESObj = ctx.service.units.encryptDES(JSON.stringify(returnData)); //加密返回数据源
            ctx.status = 500;
            ctx.body = {
                code: 1,
                msg: "error",
                data: encryptDESObj.data,
                key: encryptDESObj.publicKey
            };
        }
    };

    /**
     * 获取错误日志信息
     * @returns {Promise<void>}
     */
    async getErrorLogInfo() {
        const ctx = this.ctx;
        try {
            const fileUrl = path.join(this.config.baseDir, `app/public/errorLog`);
            if (!fs.existsSync(fileUrl)) {
                ctx.status = 200;
                ctx.body = {
                    code: 1,
                    fileList: [], //已上传的文件信息
                    msg: "未上传任何文件"
                };
            } else {
                let files = fs.readdirSync(fileUrl);
                let len = files.length;
                if (len > 0) {
                    let fileList = [];
                    for (const file of files) {
                        let filePath = path.join(fileUrl, file);
                        let stat = await fs.statSync(filePath);
                        let obj = {
                            fileName: file,
                            filePath: 'http://47.98.202.84:7001/public/errorLog/' + file,
                            tempPath:'/public/errorLog/' + file,
                            size: stat.size,
                            mtime:ctx.helper.getFormatDate(stat.mtime,'yyyy-MM-dd HH:mm:ss'),
                        }
                        fileList.push(obj);
                    }
		    fileList.sort(function(a, b) {
          		return b.mtime < a.mtime ? -1 : 1
        	    })
                    ctx.status = 200;
                    ctx.body = {
                        code: 1,
                        fileList, //已上传的文件信息
                        msg: ctx.__('getDataSuccess')
                    };
                } else {
                    ctx.status = 200;
                    ctx.body = {
                        code: 1,
                        fileList: [], //已上传的文件信息
                        msg: "未上传任何文件"
                    };
                }
            }
        } catch (err) {
            ctx.status = 500;
            ctx.body = {
                code: -1,
                msg: err.message
            };
        }
    }
}

module.exports = UploadFileController;
